# pip install fastapi[all]
# pip install imageio-ffmpeg
# pip install ffmpeg-python
# pip install requests
# pip install scenedetect
# pip install opencv-python-headless

import os
import re
import ffmpeg
import requests
import hashlib
from datetime import datetime
from fastapi import FastAPI, BackgroundTasks
from pydantic import BaseModel
from scenedetect import detect, ContentDetector
from urllib.parse import urlparse
from google_speech import GoogleSpeechTranscriber
from json_parser import extract_json_from_string
from typing import List, Dict, Optional, Any

from tiktok_downloader import VideoDownloader
from filter_video import FilterVideo

class AIRequest(BaseModel):
    timestamp: str
    rm: str
    key: str
    text: str
    type: Optional[str] = None  # 允许为空，默认为None
    prompt: Optional[str] = None  # 允许为空，默认为None
    from_text: Optional[str] = None  # 允许为空，默认为None
    history: Optional[List[Dict[str, str]]] = None  # 允许为空，默认为None

app = FastAPI()
SECRET_KEY = "ghijklmnopq"  # 与Java相同的固定密钥

# 任务状态
status = False
# 本地存储路径
# OUTPUT_MP3_DIR = "/Users/zhans.dong/data/ruoyi/mp3"
# OUTPUT_IMG_DIR = "/Users/zhans.dong/data/ruoyi/image"
# DOWNLOAD_DIR = "/Users/zhans.dong/data/ruoyi/mp4"
# OUTPUT_MP3_DIR = "E:\\ruoyi\\mp3"
# OUTPUT_IMG_DIR = "E:\\ruoyi\\image"
# DOWNLOAD_DIR = "E:\\ruoyi\\uploadPath"
OUTPUT_MP3_DIR = "/home/data/mp3"
OUTPUT_IMG_DIR = "/home/data/image"
DOWNLOAD_DIR = "/home/data/mp4"

os.makedirs(OUTPUT_MP3_DIR, exist_ok=True)
os.makedirs(OUTPUT_IMG_DIR, exist_ok=True)
os.makedirs(DOWNLOAD_DIR, exist_ok=True)


# ============================
# 1️⃣ Java 触发完整流程
# ============================
@app.get("/process-video")
async def process_video(url: str, video_id: str, language: str, background_tasks: BackgroundTasks):
    global status
    response = not status  # Java 期望返回 !status
    if status:
        return {"status": response, "message": "任务正在进行"}

    status = True
    background_tasks.add_task(video_pipeline, url, video_id, language)  # 异步执行
    return {"status": response, "message": "任务已提交"}


# ============================
# 2️⃣ 仅解析（Java 传入已下载视频）
# ============================
@app.get("/process-local-video")
async def process_local_video(video_path: str, video_id: str, language: str, background_tasks: BackgroundTasks):
    global status
    response = not status
    if status:
        return {"status": response, "message": "任务正在进行"}

    status = True
    background_tasks.add_task(parse_video_pipeline, video_path, video_id, language)
    return {"status": response, "message": "任务已提交"}


# ============================
# 3️⃣ AI 解析（Java 传入 mp3）
# ============================
@app.get("/process-ai")
async def process_ai(mp3_path: str, video_id: str, language: str, background_tasks: BackgroundTasks):
    global status
    response = not status
    if status:
        return {"status": response, "message": "任务正在进行"}

    status = True
    background_tasks.add_task(ai_pipeline, mp3_path, video_id, language)
    return {"status": response, "message": "任务已提交"}


# ============================
# 4️⃣ 视频下载 & 解析流程（异步）
# ============================
def video_pipeline(url, video_id, language):
    """ 负责完整的下载、解析、AI 处理流程 """
    try:
        # ① 下载视频
        if is_url(url):
          video_path = download_file(url, video_id)
        else:
          video_path = DOWNLOAD_DIR + url.replace('/profile/mp4', '')  # 直接使用本地路径
          video_time = get_audio_duration(video_path)
          call_java_api("DOWNLOAD", {"video_id": video_id, "video_time": video_time})
        # ② 解析视频
        if not video_path or len(video_path) <= 5:
          return
        audio_path, keyframes = extract_audio_and_frames(video_path, video_id)
        if not audio_path or len(audio_path) <= 5:
          return
        # file_size = os.path.getsize(audio_file_path)
        # if file_size > 6.99 * 1024 * 1024:
        #     return {"error": "音频文件大小不能超过 7MB，请上传更小的文件。"}
        # ③ 继续 AI 解析
        ai_pipeline(audio_path, video_id, language)

    finally:
        global status
        status = False  # 任务结束


def parse_video_pipeline(video_path, video_id, language):
    """ 负责解析本地视频 """
    try:
        audio_path, keyframes = extract_audio_and_frames(video_path, video_id)
        ai_pipeline(audio_path, video_id, language)
    finally:
        global status
        status = False



# ============================
# 5️⃣ 下载视频
# ============================

def is_url(path):
    """ 判断路径是否是URL """
    return path.startswith("http://") or path.startswith("https://")


def download_file(video_url, video_id):
    """ 下载远程文件到本地 """
    video_filename = FilterVideo.get_video_filename(video_url)
    call_java_api("DOWNLOADING", {"video_id": video_id})
    downloader = VideoDownloader(save_path=DOWNLOAD_DIR)
    video_path = downloader.download_video(video_url, custom_name=video_filename)
    if video_path and len(video_path) >= 10:
        video_time = get_audio_duration(video_path)
        call_java_api("DOWNLOAD", {"video_id": video_id, "video_path": video_path, "video_time": video_time})
        return video_path
    else:
        call_java_api("ERROR", {"video_id": video_id, "errormsg": "视频下载失败"})
        return None

# ============================
# 6️⃣ 提取音频 & 关键帧
# ============================
def extract_audio_and_frames(video_path, video_id):
    """ 提取音频和关键帧 """
    audio_path = os.path.join(OUTPUT_MP3_DIR, f"{video_id}.mp3")
    ffmpeg.input(video_path).output(audio_path, format="mp3", acodec="libmp3lame").overwrite_output().run()
#     keyframes = extract_keyframes(video_path, video_id)
    keyframes = []
    call_java_api("EXTRACT", {"video_id": video_id, "mp3": audio_path, "frames": keyframes})
    return audio_path, keyframes


# ============================
# 7️⃣ 提取关键帧
# ============================
def extract_keyframes(video_path, video_id):
    """ 提取关键帧 """
    # 2 进行场景检测
    scene_frames = []
    try:
        print(f"文件路径: {video_path}")
        # 1. 场景检测
        scenes = detect(video_path, ContentDetector())

        # 2. 创建保存关键帧的目录
        scene_folder = os.path.join(OUTPUT_IMG_DIR, video_id)
        os.makedirs(scene_folder, exist_ok=True)

        # 3. 遍历每个场景，提取关键帧
        for scene in scenes:
            transition_time = scene[0].get_seconds()  # 获取转场时间点（秒）
            minutes = int(transition_time // 60)
            seconds = int(transition_time % 60)
            time_str = f"{minutes:02d}-{seconds:02d}"
            scene_image = os.path.join(scene_folder, f"scene_{time_str}.jpg")

            # 使用 ffmpeg 提取单帧图像
            ffmpeg.input(video_path, ss=transition_time).output(
                scene_image, vframes=1
            ).overwrite_output().run(capture_stdout=True, capture_stderr=True)

            scene_frames.append({"time": int(transition_time), "path": scene_image})

    except Exception as e:
        print(f"[ERROR] 提取关键帧失败: {str(e)}")
        return []  # 出现错误时返回空列表

    return scene_frames


def ai_pipeline(audio_path, video_id, language):
    """ 负责 AI 解析 """
    try:
        # 这里等待你提供 Google AI 接口
        transcriber = GoogleSpeechTranscriber("zeta-courage-452114-u1")
        result = transcriber.transcribe_audio(audio_path, language)
        call_java_api("END", {"video_id": video_id, "ai_data": result})
    finally:
        global status
        status = False


# ============================
# 8️⃣ 调用 Java 接口
# ============================
def call_java_api(status, data):
    """ 调用 Java 系统 API，更新状态 """
    print(f"状态: {status}")
    print(f"data: {data}")
    java_api_url = "http://serverapp:8080/video-analysis/public/fghijklmnop/change-status"
    try:
        requests.post(java_api_url, json={"status": status, "data": data})
    except Exception as e:
        print(f"调用 Java 失败: {e}")


# ============================
# Java 调用AI
# ============================
@app.post("/ai-process")
async def ai_process(request: AIRequest):
    # 现在所有参数都在request对象中
    timestamp = request.timestamp
    rm = request.rm
    key = request.key
    text = request.text
    type = request.type
    prompt = request.prompt
    from_text = request.from_text
    history = request.history

    # 1. 准备数据并排序
    data_list = [str(timestamp), rm, SECRET_KEY]
    data_list.sort()

    # 2. 拼接字符串
    combined = ''.join(data_list)

    # 3. SHA-256加密
    computed_signature = hashlib.sha256(combined.encode()).hexdigest()
    print_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print(f"[{print_time}] : 比较签名")
    # 4. 比较签名
    if computed_signature != key:
        # 签名不匹配，返回404错误
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail={
                "error": "Signature verification failed",
                "message": "无效的验证密钥",
                "received_signature": key,
                "computed_signature": computed_signature
            }
        )
    transcriber = GoogleSpeechTranscriber("zeta-courage-452114-u1")
    result = transcriber.transcribe(text, prompt, type, history)
    print_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print(f"[{print_time}] : 调用结束")
    return {"status": 200, "message": result}

def get_audio_duration(audio_path):
    # 使用ffprobe获取音频文件信息
    probe = ffmpeg.probe(audio_path)
    # 从音频流中找到时长
    duration = float(probe['format']['duration'])
    return duration

# ============================
# Java 调用AI
# ============================
@app.get("/ytb-download")
async def ytb_download(url: str):
    video_filename = FilterVideo.get_video_filename(url)
    downloader = VideoDownloader(save_path=DOWNLOAD_DIR_YTB)
    video_path = downloader.download_video(url, custom_name=video_filename)
    return {"status": 200, "message": video_path}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000, reload=True)

# uvicorn index:app --host 0.0.0.0 --port 8000 --reload